﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ColliderView : MonoBehaviour
{
	[System.NonSerialized]
	public bool showInPlaying;
	public bool showWireFrame = true;
	public bool showSphere = true;
	public bool showBox = true;
	public bool showCapsule = true;
	public bool showMesh = true;
	public bool showCharacter = true;

	public Color sphereColor = Color.cyan;
	public Color boxColor = Color.yellow;
	public Color capsuleColor = Color.red;
	public Color meshColor = Color.grey;
	public Color characterColor = Color.blue;
	[Range(0, 1)] public float alpha = 0.5f;

	private Mesh cylinderMesh;
	private Mesh hemiSphereMesh;

	void OnDrawGizmos()
	{
		if (!showInPlaying && Application.isPlaying)
		{
			return;
		}
			
		Collider[] colliders = GameObject.FindObjectsOfType<Collider>();
		for (int i = 0; i < colliders.Length; i++)
		{
			Collider collider = colliders[i];
			if (showSphere && collider is SphereCollider)
			{
				Color c = sphereColor;
				c.a *= alpha;
				Gizmos.color = c;
				SphereCollider sphereCollider = collider as SphereCollider;
				Gizmos.matrix = collider.transform.localToWorldMatrix;
				Gizmos.DrawSphere(sphereCollider.center, sphereCollider.radius);
				if (showWireFrame)
				{
					Gizmos.DrawWireSphere(sphereCollider.center, sphereCollider.radius);
				}
			}
			else if (showBox && collider is BoxCollider)
			{
				Color c = boxColor;
				c.a *= alpha;
				Gizmos.color = c;
				BoxCollider boxCollider = collider as BoxCollider;
				Gizmos.matrix = collider.transform.localToWorldMatrix;
				Gizmos.DrawCube(boxCollider.center, boxCollider.size);
				if (showWireFrame)
				{
					Gizmos.DrawWireCube(boxCollider.center, boxCollider.size);
				}
			}
			else if (showCapsule && collider is CapsuleCollider)
			{
				Color c = capsuleColor;
				c.a *= alpha;
				Gizmos.color = c;

				CapsuleCollider capsuleCollider = collider as CapsuleCollider;
				DrawCapsule(capsuleCollider.transform.localToWorldMatrix, capsuleCollider.center, capsuleCollider.height, capsuleCollider.radius);
			}
			else if (showMesh && collider is MeshCollider)
			{
				Color c = meshColor;
				c.a *= alpha;
				Gizmos.color = c;
				MeshCollider meshCollider = collider as MeshCollider;
				Gizmos.matrix = collider.transform.localToWorldMatrix;
				Gizmos.DrawMesh(meshCollider.sharedMesh);
				if (showWireFrame)
				{
					Gizmos.DrawWireMesh(meshCollider.sharedMesh);
				}
			}
		}

		if (showCharacter)
		{
			CharacterController[] characters = GameObject.FindObjectsOfType<CharacterController>();
			for (int i = 0; i < characters.Length; i++)
			{
				CharacterController character = characters[i];
				Color c = characterColor;
				c.a *= alpha;
				Gizmos.color = c;

//			Matrix4x4 m = Matrix4x4.TRS(character.transform.position, Quaternion.identity, character.transform.localScale);
//			Transform p = character.transform.parent;
//			if (p != null)
//			{
//				m = Matrix4x4.TRS(p.position, Quaternion.identity, p.localScale) * m;
//				p = p.parent;
//			}
				DrawCapsule(character.transform.localToWorldMatrix, character.center, character.height, character.radius);
			}
		}
	}

	void DrawCapsule(Matrix4x4 t, Vector3 center, float height, float radius)
	{
		Matrix4x4 m = t * Matrix4x4.Translate(center);
		float xzScale = radius / 0.5f;
		float bodyHeight = height - radius * 2;
		bodyHeight = Mathf.Max(bodyHeight, 0);
		if (radius * 2 < height)
		{
			Mesh bodyMesh = GetCylinderMesh();
			Matrix4x4 bodyMatrix = m * Matrix4x4.Scale(new Vector3(xzScale, bodyHeight / 2, xzScale));
			Gizmos.matrix = bodyMatrix;
			Gizmos.DrawMesh(bodyMesh);
			if (showWireFrame)
			{
				Gizmos.DrawWireMesh(bodyMesh);
			}
		}

		Mesh headAndFootMesh = GetHemiSphereMesh();

		Matrix4x4 headMatrix = Matrix4x4.Translate(new Vector3(0, bodyHeight / 2, 0)) * Matrix4x4.Scale(new Vector3(xzScale, xzScale, xzScale));
		Gizmos.matrix = m * headMatrix;
		Gizmos.DrawMesh(headAndFootMesh);
		if (showWireFrame)
		{
			Gizmos.DrawWireMesh(headAndFootMesh);
		}

		Matrix4x4 footMatrix = Matrix4x4.Translate(new Vector3(0, -bodyHeight / 2, 0)) * Matrix4x4.Scale(new Vector3(xzScale, -xzScale, xzScale));
		Gizmos.matrix = m * footMatrix;
		Gizmos.DrawMesh(headAndFootMesh);
		if (showWireFrame)
		{
			Gizmos.DrawWireMesh(headAndFootMesh);
		}
	}

	Mesh GetCylinderMesh()
	{
		if (cylinderMesh == null)
		{
			GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
			MeshFilter filter = obj.GetComponent<MeshFilter>();
			cylinderMesh = filter.sharedMesh;
			GameObject.DestroyImmediate(obj);
		}
		return cylinderMesh;
	}

	Mesh GetHemiSphereMesh()
	{
		if (hemiSphereMesh == null)
		{
			GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Sphere);
			MeshFilter filter = obj.GetComponent<MeshFilter>();
			hemiSphereMesh = filter.sharedMesh;
			hemiSphereMesh = GameObject.Instantiate(hemiSphereMesh);
			Vector3[] vertices = hemiSphereMesh.vertices;
			int[] indices = hemiSphereMesh.triangles;

			int minusCount = 0;
			for (int i = 0; i < indices.Length; i += 3)
			{
				int index0 = indices[i];
				int index1 = indices[i + 1];
				int index2 = indices[i + 2];

				Vector3 vertex0 = vertices[index0];
				Vector3 vertex1 = vertices[index1];
				Vector3 vertex2 = vertices[index2];

				Vector3 v1 = vertex1 - vertex0;
				Vector3 v2 = vertex2 - vertex0;
				Vector3 c = Vector3.Cross(v1, v2);
				if (c.y < 0)
				{
					indices[i] = -1;
					indices[i + 1] = -1;
					indices[i + 2] = -1;
					minusCount += 3;
				}
			}

			int newI = 0;
			int[] newIndices = new int[indices.Length - minusCount];
			for (int i = 0; i < indices.Length; i++)
			{
				if (indices[i] >= 0)
				{
					newIndices[newI++] = indices[i];
				}
			}
			hemiSphereMesh.triangles = newIndices;

			GameObject.DestroyImmediate(obj);
		}
		return hemiSphereMesh;
	}
}
